package com.pignest.hotel.ui.reception;

import java.util.ArrayList;
import java.util.Date;
import java.util.List;

import org.apache.commons.lang.StringUtils;
import org.zkoss.zk.ui.Component;
import org.zkoss.zk.ui.event.Event;
import org.zkoss.zk.ui.event.EventListener;
import org.zkoss.zk.ui.event.Events;
import org.zkoss.zk.ui.util.Clients;
import org.zkoss.zkex.zul.Borderlayout;
import org.zkoss.zul.Button;
import org.zkoss.zul.Datebox;
import org.zkoss.zul.Label;
import org.zkoss.zul.Listbox;
import org.zkoss.zul.Listcell;
import org.zkoss.zul.Listitem;
import org.zkoss.zul.Textbox;

import com.pignest.framework.util.Utils;
import com.pignest.hotel.beans.Card;
import com.pignest.hotel.beans.Living;
import com.pignest.hotel.beans.LivingSpecifics;
import com.pignest.hotel.beans.Member;
import com.pignest.hotel.beans.Room;
import com.pignest.hotel.beans.TbAccounts;
import com.pignest.hotel.definition.ChargeOpType;
import com.pignest.hotel.definition.InComeItemType;
import com.pignest.hotel.definition.LivingState;
import com.pignest.hotel.definition.LivingType;
import com.pignest.hotel.definition.OperateState;
import com.pignest.hotel.definition.PayMethod;
import com.pignest.hotel.definition.RoomLiveStatus;
import com.pignest.hotel.global.picker.Receiver;
import com.pignest.hotel.service.CardService;
import com.pignest.hotel.service.ReceptionService;
import com.pignest.hotel.service.RoomService;
import com.pignest.hotel.spring.Services;
import com.pignest.hotel.system.Config;
import com.pignest.hotel.system.Global;
import com.pignest.hotel.system.Hotel;
import com.pignest.hotel.system.L;
import com.pignest.hotel.system.Logic;
import com.pignest.hotel.ui.member.MemberPicker;
import com.pignest.hotel.ui.room.RoomHistogram;
import com.pignest.hotel.util.DateUtil;
import com.pignest.hotel.util.UIUtils;

public class QuickLiving extends Borderlayout implements EventListener, Receiver<Member> {
	private static final long serialVersionUID = -127468017456204435L;
	
	private static final String ACTION_WRITE_CARD = "write_card";
	private static final String ACTION_READ_MEMBER_CARD = "member";

	private int step = 1;
	private Component step1, step2, step3;
	private RoomHistogram histogram;
	private Button nextButton;
	private Listbox livingList, livingList2;
	
	private Textbox roomTextbox;
	private Textbox nameTextbox;
	private Textbox cidTextbox;
	private Textbox priceTextbox;
	private Datebox leavingDatebox;
	private Listbox leavingTimebox;
	private Label card1, card2, card3;
	private Textbox depositTextbox;
	private Listbox openRoomTypeListbox;
	private Textbox remarkTextbox;
	private Textbox memberTextbox;
	private Listbox payMethodListbox;
	
	private List<Living> livings;
	private Card[] cards;
	private Card currentCard;
	private int selectedIndex;
	private Member member;
	
	public QuickLiving() {
		addEventListener(Events.ON_CREATE, this);
	}
	
	private void onCreate() {
		histogram = (RoomHistogram) getFellow("roomHistogram");
		nextButton = (Button) getFellow("nextButton");
		step1 = getFellow("step1");
		step2 = getFellow("step2");
		step3 = getFellow("step3");
		livingList = (Listbox)getFellow("livingList");
		livingList2 = (Listbox)getFellow("livingList2");
		
		roomTextbox = (Textbox) getFellow("roomName");
		nameTextbox = (Textbox) getFellow("customName");
		cidTextbox = (Textbox) getFellow("certificateNO");
		priceTextbox = (Textbox) getFellow("price");
		leavingDatebox = (Datebox) getFellow("leavingDate");
		leavingTimebox = (Listbox) getFellow("leavingTime");
		depositTextbox = (Textbox) getFellow("deposit");
		openRoomTypeListbox = (Listbox) getFellow("openRoomType");
		remarkTextbox = (Textbox) getFellow("remark");
		memberTextbox = (Textbox) getFellow("member");
		payMethodListbox = (Listbox) getFellow("payMethod");
		
		card1 = (Label) getFellow("card1");
		card2 = (Label) getFellow("card2");
		card3 = (Label) getFellow("card3");
		
		livings = new ArrayList<Living>();
	}
	
	private void onStep2() {
		List<String> selected = histogram.getSelected();
		if (selected == null || selected.isEmpty()) {
			showResult("请选择房间");
			return;
		}
		if (selected.size() == 1) {
			showResult("散客入住请从房态图上直接入住.");
			return;
		}
		livingList.getItems().clear();
		RoomService roomService = Services.getRoomService();
		for (int i=0, j=selected.size(); i<j; i++) {
			String roomId = selected.get(i);
			Room room = roomService.getRoom(roomId);
			if (room == null) {
				showResult("内部错误, 请刷新后重试");
				return;
			}
			if (!Logic.canLiving(room)) {
				showResult("房间" + room.getName() + "目前的状态不能入住");
				return;
			}
			Living l = new Living();
			l.setRoom(room);
			l.setRoomPrice(room.getType().getPrice());
			l.setAdjustPrice(l.getRoomPrice());
			l.setLiveType(LivingType.TEAM.name());
			l.setMaster(i == 0);
			l.setTeamState(Living.TEAM_STATE_NEED_PATCH);
			livings.add(l);
			
			Listitem item = toListitem(l, null);
			if (item != null)
				item.setParent(livingList);
		}
		depositTextbox.setValue(Utils.toPrice(Config.getDefaultDeposit() * livings.size()));
		step1.setVisible(false);
		step2.setVisible(true);
		step = 2;
	}
	
	private void onStep3() {
		if (!Hotel.onDuty()) {
			showResult("您当前不在值班状态, 不能进行些操作");
			return;
		}
		Date d = leavingDatebox.getValue();
		String time = UIUtils.getSelectedLable(leavingTimebox);
		Date leavingDate = d == null ? null : DateUtil.parseDate(d, time);
		long now = System.currentTimeMillis();
		if (leavingDate == null || leavingDate.getTime() <= now) {
			showResult("请选择合适的预离时间");
			return;
		}
		if (!Utils.checkPrice(depositTextbox.getValue())) {
			showResult("请输入压金, 不收压金则请输入0");
			return;
		}
		int deposit = Utils.toPrice(depositTextbox.getValue());
		final String payMethod = UIUtils.getSelectedValue(payMethodListbox);
		if (PayMethod.MEMBER_CARD.is(payMethod)) {
			if (member == null) {
				showResult("选择会员支付, 请选择会员");
				return;
			}
		}
		String openRoomType = UIUtils.getSelectedValue(openRoomTypeListbox);
		
		StringBuilder sb = new StringBuilder();
		sb.append("快速开房 " + livings.size() + " 个房间");
		sb.append(", 入住到 ").append(DateUtil.toString(leavingDate, DateUtil.HOTEL_DEFAULT_FORMAT));
		sb.append(", 收取压金 " + Utils.toPrice(deposit)).append(" 元");
		sb.append(". \n\n请确认!");
		if (!UIUtils.confirm(sb.toString()))
			return;
		
		final int money = deposit;
		Date _now = new Date(now);
		String remark = StringUtils.defaultIfEmpty(remarkTextbox.getValue(), null);
		Living masterLiving = null;
		for (Living v : livings) {
			v.setLiveState(LivingState.LIVING.name());
			v.setLiveTime(_now);
			v.setExpectLeaveDate(leavingDate);
			v.setGrantDate(leavingDate);
			v.setOpenRoomType(openRoomType);
			v.setRemark(remark);
			if (v.isMaster())
				masterLiving = v;
		}
		if (masterLiving == null)
			masterLiving = livings.get(0);
		masterLiving.setStorage(deposit);
		masterLiving.setAvailable(deposit);
		
		final Living ml = masterLiving;
		final ReceptionService service = Services.getReceptionService();
		service.executeInTransaction(new Runnable() {
			@Override
			public void run() {
				RoomService roomService = Services.getRoomService();
				String serialNumber = Global.getLivineSerialNumber();
				List<Room> rooms = new ArrayList<Room>();
				Date now = new Date();
				for (Living v : livings) {
					v.setSerialNumber(serialNumber);
					service.insert(v);
					
					LivingSpecifics spec = new LivingSpecifics();
					spec.setLiving(v);
					spec.setOperateDate(now);
					spec.setOperateType(OperateState.LIVING.name());
					spec.setRoom(v.getRoom().getName());
					spec.setRoomPrice(v.getAdjustPrice());
					spec.setGrantDate(v.getGrantDate());
					spec.setLeaveDate(spec.getGrantDate());
					spec.setRemark("团队");
					if (v.isMaster()) {
						spec.setPay(v.getStorage());
						spec.setPaymentMethod(payMethod);
						
						TbAccounts account = new TbAccounts();
						account.setLiving(v);
						account.setPrice(v.getStorage());
						account.setType(InComeItemType.YJ.name());
						account.setOptime(now);
						account.setEndstate("否");
						account.setOpdate(DateUtil.toString(now, DateUtil.DEFAULT_DATE_FORMAT));
						account.setPrice2(v.getAdjustPrice());
						account.setOpUser(Hotel.getCurrentUser().getName());
						service.insert(account);
					} else {
						spec.setRemark("团" + ml.getRoom().getName());
					}
					service.insert(spec);
					
					L.insert(v, "团队入住");
					Room room = roomService.getRoom(v.getRoom().getId());
					room.setLiveStatus(RoomLiveStatus.FILLED.name());
					rooms.add(room);
				}
				roomService.saveAll(rooms);
				Hotel.receive(money, ChargeOpType.OnConsume, PayMethod.CASH, "团队入住压金");
			}
		});
		cards = new Card[livings.size()];
		for (int i=0, j=livings.size(); i<j; i++) {
			Living l = livings.get(i);
			Listitem item = toListitem(l, "");
			item.setParent(livingList2);
		}
		
		step2.setVisible(false);
		step3.setVisible(true);
		nextButton.setLabel("完成");
		nextButton.setImage("/images/16x16/finish.png");
		getFellow("cancelButton").setVisible(false);
		step = 3;
	}
	
	public void onUser(Object data) {
		if (!(data instanceof String[])) {
			showResult("数据错误");
			return;
		}
		String[] strs = (String[])data;
		String action = strs[0];
		if (ACTION_WRITE_CARD.equals(action)) {
			boolean success = "true".equals(strs[2]);
			if (success) {
				if (!strs[1].equals(currentCard.getSerialNumber())) {
					showResult("数据错误, 请按顺序处理");
					return;
				}
				Living l = livings.get(selectedIndex);
				Room room = Services.getRoomService().getRoom(l.getRoom().getId());
				Services.getCardService().grantCard(strs[1], room, l.getGrantDate());
				cards[selectedIndex] = currentCard;
				((Listcell)livingList2.getItemAtIndex(selectedIndex).getChildren().get(6)).setLabel(currentCard.getCardNumber());
				currentCard = null;
				selectedIndex = -1;
				showResult("发卡成功");
			} else {
				showResult("发卡失败");
			}
		} else if (ACTION_READ_MEMBER_CARD.equals(action)) {
			String serial = strs[1];
			Card card = Services.getCardService().getCardBySerialNumber(serial);
			if (card == null || !card.isEnable()) {
				showResult("无效卡");
				return;
			}
			if (card.getType() != Card.TYPE_MEMBER) {
				showResult("不是会员卡");
				return;
			}
			Member m = Services.getMemberService().getMemberByCardNumber(card.getCardNumber());
			if (m == null) {
				showResult("无效会员卡");
				return;
			}
			onPicked(m);
		}
	}
	
	public void onReadCard(String cardSerial) {
		if (StringUtils.isEmpty(cardSerial))
			return;
		CardService cardService = Services.getCardService();
		Card card = cardService.getCardBySerialNumber(cardSerial);
		if (card == null || !card.isEnable()) {
			UIUtils.alert("无效卡");
			return;
		}
		currentCard = card;
		card1.setValue(card.getCardNumber());
		card2.setValue(card.getHolderName2());
		card3.setValue(card.getExpireTime2());
	}
	
	public void onWriteCard() {
		if (currentCard == null) {
			showResult("请先刷卡");
			return;
		}
		int index = livingList2.getSelectedIndex();
		if (index == -1 || index >= cards.length)
			return;
		if (cards[index] != null)
			return;
		Listitem item = livingList2.getSelectedItem();
		if (item == null)
			return;
		Living l = (Living)item.getValue();
		if (l == null)
			return;
		
		selectedIndex = index;
		String serial = currentCard.getSerialNumber();
		String lock = l.getRoom().getLockNumber();
		String time = DateUtil.toString(l.getGrantDate(), Card.DATE_FORMAT);
		StringBuilder sb = new StringBuilder();
		sb.append("writeCard('").append(ACTION_WRITE_CARD).append("','").append(serial).append("','");
		sb.append(lock).append("','").append(time).append("');");
		Clients.evalJavaScript(sb.toString());
	}
	
	public void onSaveLiving() {
		Listitem item = livingList.getSelectedItem();
		if (item == null)
			return;
		Living l = (Living)item.getValue();
		if (l == null)
			return;
		l.setCustormName(StringUtils.defaultIfEmpty(nameTextbox.getValue(), null));
		l.setPassportNumber(StringUtils.defaultIfEmpty(cidTextbox.getValue(), null));
		l.setAdjustPrice(Utils.toPrice(priceTextbox.getValue()));
		updateListitem(item);
	}
	
	@SuppressWarnings("unchecked")
	public void onUnitePrices() {
		Listitem item = livingList.getSelectedItem();
		if (item == null)
			return;
		Living l = (Living)item.getValue();
		if (l == null)
			return;
		int price = l.getAdjustPrice();
		for (Living v : livings) {
			v.setAdjustPrice(price);
		}
		List<Listitem> items = livingList.getItems();
		for (Listitem i : items) {
			updateListitem(i);
		}
	}
	
	@SuppressWarnings("unchecked")
	public void setTeamLeader() {
		Listitem item = livingList.getSelectedItem();
		if (item == null)
			return;
		Living l = (Living)item.getValue();
		if (l == null)
			return;
		for (Living v : livings) {
			v.setMaster(false);
		}
		l.setMaster(true);
		List<Listitem> items = livingList.getItems();
		for (Listitem i : items) {
			updateListitem(i);
		}
	}
	
	public void onSelected() {
		Listitem item = livingList.getSelectedItem();
		if (item == null)
			return;
		Living l = (Living)item.getValue();
		if (l == null)
			return;
		roomTextbox.setValue(l.getRoom().getName());
		nameTextbox.setValue(l.getCustormName());
		cidTextbox.setValue(l.getPassportNumber());
		priceTextbox.setValue(Utils.toPrice(l.getAdjustPrice()));
	}
	
	private Listitem toListitem(Living l, String cardNumber) {
		Room room = l.getRoom();
		Listitem item = new Listitem();
		item.setValue(l);
		item.appendChild(new Listcell(room.getName()));
		item.appendChild(new Listcell(room.getType().getName()));
		item.appendChild(new Listcell(Utils.toPrice(l.getRoomPrice())));
		item.appendChild(new Listcell(Utils.toPrice(l.getAdjustPrice())));
		item.appendChild(new Listcell(l.getCustormName()));
		item.appendChild(new Listcell(l.isMaster() ? "是" : ""));
		if (cardNumber != null) {
			item.appendChild(new Listcell(cardNumber));
		}
		return item;
	}
	
	private void updateListitem(Listitem item) {
		Living l = (Living)item.getValue();
		((Listcell)item.getChildren().get(3)).setLabel(Utils.toPrice(l.getAdjustPrice()));
		((Listcell)item.getChildren().get(4)).setLabel(l.getCustormName());
		((Listcell)item.getChildren().get(5)).setLabel(l.isMaster() ? "是" : "");
	}
	
	public void onNext() {
		if (step == 1) {
			onStep2();
		} else if (step == 2) {
			onStep3();
		} else if (step == 3) {
			int n = 0;
			for (int i = 0; i < cards.length; i++) {
				if (cards[i] == null)
					n ++;
			}
			if (n > 0) {
				String msg = "还有 " + n + " 个房间未配卡, 是否继续? \n\n选'是'将退出当前入住, 选'否'继续操作.";
				if (!UIUtils.confirm(msg))
					return;
			}
			UIUtils.refresh();
		}
	}
	
	public void onPickMember() {
		MemberPicker.pickMember(this);
	}
	
	@Override
	public void onPicked(Member o) {
		this.member = o;
		memberTextbox.setValue(o == null ? null : o.getDisplayName());
		//update price
	}
	
	@Override
	public Member getPicked() {
		return member;
	}
	
	private void showResult(String msg) {
		UIUtils.alert(msg);
	}
	
	public void onCancel() {
		UIUtils.refresh();
	}
	
	@Override
	public void onEvent(Event event) throws Exception {
		if (Events.ON_CREATE.equals(event.getName())) {
			onCreate();
		}
	}
	
}
